/********************************************************************************
  * @file    newprojectwizard.cpp
  * @author  Lun Li
  * @version V2.2.0
  * @date    2022.7.8
  * @brief   This file provides all the NewProjectWizard functions.
  *******************************************************************************/

#include "newprojectwizard.h"

NewProjectWizard::NewProjectWizard(ProgramConfig *const config, QWidget *parent) :
    QWizard(parent)
{
    // 初始化页面
    page1 = new NewProjectPage1(config);
    page2 = new NewProjectPage2(config, page1);
    addPage(page1);
    addPage(page2);

    // 设置属性
    setWindowTitle(tr("New Project Wizard"));
    setWizardStyle(QWizard::ClassicStyle);
    setAttribute(Qt::WA_DeleteOnClose);
}

void NewProjectWizard::accept()
{
    QString projectName = page1->projectName();
    QString projectPath = page1->projectPath();
    QString projectComment = page1->projectComment();

    // 工程文件
    QString filePath = QDir(projectPath).absoluteFilePath(projectName + ".proj");
    QSettings projFile(filePath, QSettings::IniFormat);

    // 向工程文件内写入工程信息
    projFile.setValue("Properties/projectName", projectName);
    projFile.beginGroup("Sources");
    for (const QString &path : page2->copySources()) {
        projFile.setValue(QFileInfo(path).fileName(),
                          path + "," + QString::number(ProjectItem::NoCompiled) + ",");
    }
    projFile.endGroup();
    projFile.setValue("Comment/description", projectComment);

    close();
    emit wizardFinished(filePath);
}

NewProjectPage1::NewProjectPage1(ProgramConfig *const config, QWidget *parent) :
    QWizardPage(parent),
    m_config(config)
{
    // 初始化各部件
    QLabel *projectNameLabel = new QLabel(tr("Project Name:"));
    projectNameEdit = new QLineEdit;
    projectPathEdit = new ShowDirLineEdit(tr("Project Path:"), tr("Browse"));
    QLabel *projectCommentLabel = new QLabel(tr("Project Comment:"));
    projectCommentEdit = new QTextEdit;

    // 设置布局
    setLayout(new NoMarginVBoxLayout);
    layout()->addWidget(projectNameLabel);
    layout()->addWidget(projectNameEdit);
    layout()->addWidget(projectPathEdit);
    layout()->addWidget(projectCommentLabel);
    layout()->addWidget(projectCommentEdit);
    setTitle(tr("Specify project name and path"));

    // 初始化上一级目录
    upPath = QDir::currentPath();
    projectPathEdit->setText(upPath);

    // 信号槽连接
    // 工程名改变时，自动改变工程路径对应的文件夹名
    connect(projectNameEdit, &QLineEdit::textChanged, this, [=](const QString &text) {
        projectPathEdit->setText(upPath + "/" + text);
        emit completeChanged();
    });
    // 工程路径改变时，同时改变上一级目录
    connect(projectPathEdit, &ShowDirLineEdit::textEdited, this, [=](const QString &text) {
        upPath = text;
        emit completeChanged();
    });
    // 用户点击浏览目录按钮时，弹出浏览窗口并设置路径
    connect(projectPathEdit->button(), &QPushButton::clicked, this, [=]() {
        QString projectPath = QFileDialog::getExistingDirectory(this, tr("Add Sources"), m_config->lastOpenPath());
        if (projectPath.isEmpty()) {
            return;
        }
        m_config->setLastOpenPath(projectPath);
        upPath = projectPath;
        projectPathEdit->setText(QDir(projectPath).absoluteFilePath(projectNameEdit->text()));
    });
}

bool NewProjectPage1::validatePage()
{
    QDir dir;
    if (dir.exists(projectPathEdit->text())) { // 若工程路径已存在，提醒用户是否替换原工程文件
        int ans = QMessageBox::question(this, tr("New Project Wizard"), tr("Project \"%1\" is already existed, replace it?").arg(projectName()),
                                        QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
        if (ans == QMessageBox::Cancel) {
            return false;
        }
    }
    if (!dir.mkpath(projectPathEdit->text())) { // 创建工程文件夹
        QMessageBox::critical(this, tr("New Project Wizard"), tr("Cannot make path: %1").arg(projectPath()));
        return false;
    }
    QString srcPath = QDir(projectPathEdit->text()).absoluteFilePath("src");
    if (!dir.mkpath(srcPath)) { // 创建工程文件夹下的src文件夹
        QMessageBox::critical(this, tr("New Project Wizard"), tr("Cannot make path: %1").arg(QDir::toNativeSeparators(srcPath)));
        return false;
    }
    QString compilePath = QDir(projectPathEdit->text()).absoluteFilePath("compile");
    if (!dir.mkpath(compilePath)) { // 创建工程文件夹下的compile文件夹
        QMessageBox::critical(this, tr("New Project Wizard"), tr("Cannot make path: %1").arg(QDir::toNativeSeparators(compilePath)));
        return false;
    }
    return true;
}

bool NewProjectPage1::isComplete() const
{
    return !projectName().isEmpty() && !projectPath().isEmpty();
}

QString NewProjectPage1::projectName() const
{
    return projectNameEdit->text();
}

QString NewProjectPage1::projectPath() const
{
    return projectPathEdit->text();
}

QString NewProjectPage1::projectComment() const
{
    return projectCommentEdit->toPlainText();
}

NewProjectPage2::NewProjectPage2(ProgramConfig *const config, NewProjectPage1 *page1, QWidget *parent) :
    QWizardPage(parent),
    page1(page1),
    m_config(config)
{
    // 初始化部件与布局
    fileListView = new ShowDirListView(tr("Source List:"), tr("Add"), tr("Remove"));
    setLayout(new NoMarginHBoxLayout);
    layout()->addWidget(fileListView);
    setTitle(tr("Add Sources"));

    // 按下添加按钮时，弹出文件目录浏览窗口
    connect(fileListView->addButton(), &QPushButton::clicked, this, [=]() {
        QStringList sourcePaths = QFileDialog::getOpenFileNames(this, tr("Add Sources"), m_config->lastOpenPath(), "Verilog (*.v)");
        if (sourcePaths.isEmpty()) {
            return;
        }
        m_config->setLastOpenPath(sourcePaths.at(0));
        fileListView->addDirs(sourcePaths);
    });

    // 按下移除按钮时，移除选定的文件
    connect(fileListView->removeButton(), &QPushButton::clicked, fileListView, &ShowDirListView::removeSelectedDirs);
}

QStringList NewProjectPage2::copySources()
{
    QStringList ret;
    for (const QString &dir : fileListView->dirs()) {
        // 将文件都复制到src文件夹下
        QString newPath = QDir(page1->projectPath()).absoluteFilePath("src/" + QFileInfo(dir).fileName());
        if (!QFile::copy(dir, newPath)) {
            QMessageBox::critical(this, tr("New Project Wizard"), tr("Cannot copy\n"
                                                                     "%1\n"
                                                                     "to\n"
                                                                     "%2.").arg(dir, newPath));
            continue;
        }
        ret << newPath;
    }
    return ret;
}
